package klog

import (
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"fmt"
	"gitee.com/klogsdk/klog-go-sdk/credentials"
	awsCred "github.com/aws/aws-sdk-go/aws/credentials"
	v4 "github.com/aws/aws-sdk-go/aws/signer/v4"
	"io"
	"net/http"
	"sort"
	"strings"
	"time"
)

func signatureV2(req *http.Request, cred *credentials.Credentials) error {
	c, err := cred.Get()
	if err != nil {
		return fmt.Errorf("signatureV2 error, err=%w", err)
	}
	h := hmac.New(sha1.New, []byte(c.SecretAccessKey))

	h.Write([]byte(req.Method))
	h.Write([]byte("\n"))

	if len(req.Header["Content-Md5"]) > 0 {
		h.Write([]byte(req.Header["Content-Md5"][0]))
	}
	h.Write([]byte("\n"))

	if len(req.Header["Content-Type"]) > 0 {
		h.Write([]byte(req.Header["Content-Type"][0]))
	}
	h.Write([]byte("\n"))

	if len(req.Header["Date"]) > 0 {
		h.Write([]byte(req.Header["Date"][0]))
	}
	h.Write([]byte("\n"))

	var kLogHeaderKeys []string
	for k := range req.Header {
		k = strings.ToLower(k)
		if strings.HasPrefix(k, "x-klog") {
			kLogHeaderKeys = append(kLogHeaderKeys, k)
		}
	}
	sort.Strings(kLogHeaderKeys)
	for i := range kLogHeaderKeys {
		h.Write([]byte(kLogHeaderKeys[i]))
		h.Write([]byte(":"))
		h.Write([]byte(req.Header.Get(kLogHeaderKeys[i])))
		h.Write([]byte("\n"))
	}

	h.Write([]byte(req.URL.RequestURI()))
	req.Header.Set("Authorization", "KLOG "+c.AccessKeyID+":"+base64.StdEncoding.EncodeToString(h.Sum(nil)))
	return nil
}

func signatureV4(cred *credentials.Credentials, region string, r *http.Request, body io.ReadSeeker) error {
	return signatureV4WithService(cred, region, "klog", r, body)
}

func signatureV4WithService(cred *credentials.Credentials, region, service string, r *http.Request, body io.ReadSeeker) error {
	var bodyBak = r.Body
	var headerBak = r.Header.Clone()
	for k, v := range r.Header {
		headerBak[k] = v
	}
	for k := range headerBak {
		k = strings.ToLower(k)
		if !strings.HasPrefix(k, "x-klog") {
			r.Header.Del(k)
		}
	}

	val, err := cred.Get()
	if err != nil {
		return fmt.Errorf("signatureV4 error, err=%w", err)
	}

	awsSc := awsCred.NewStaticCredentials(val.AccessKeyID, val.SecretAccessKey, val.SessionToken)
	signer := v4.NewSigner(awsSc)

	if headerBak.Get("Content-Md5") != "" && body != nil {
		_, err = signer.Sign(r, body, service, region, time.Now())
	} else {
		_, err = signer.Sign(r, nil, service, region, time.Now())
	}
	if err != nil {
		return fmt.Errorf("signatureV4 error, err=%w", err)
	}
	r.Body = bodyBak
	for k, v := range headerBak {
		r.Header.Set(k, v[0])
	}
	return nil
}
